# -*- coding:utf-8 -*-

from pydantic import BaseModel
from fastapi import Depends, Request, HTTPException, status
from fastapi.security import SecurityScopes

from core.exceptions import ServiceException

from utils.password import password_hash, virify_password
from utils.jwt import get_token_data
from utils.dependence import PageFilter
from utils.logger import logger

from crud.user import UserDao
from services.base import BaseService
from schemas.user import User, UserCreate, UserPasswordIn, UserAll


class UserService(BaseService):
    def __init__(self, dao = Depends(UserDao)):
        self.dao = dao
        self.SCHEMA = UserAll

    async def create(self, request: Request, data: UserCreate):
        filter, in_, like, order_by= self.dao.filter(PageFilter(None, {'account': data.account, 'email': data.email, 'mobile': data.mobile}, None, None))
        count = await self.dao.count(filter=filter)
        if count > 0:
            raise HTTPException(status_code=409, detail=f"账户已存在")
        create_user = self.get_current_user(request).id
        # 封装
        data = UserAll(**data.dict(), create_user=create_user)
        data.password = password_hash(data.password)
        data.status = 0
        data.avatar = 'https://avatars.githubusercontent.com/u/17774994?v=4'
        data_db = await self.dao.add(data)
        return data_db

    async def get_role_permisions_by_user_id(self, user_id: int):
        roles = await self.get_roles_by_user_id(user_id)
        if roles:
            permisions = await self.dao.get_ref([role.id for role in roles], 'tb_permision', 'role_permision')
            for role in roles:
                role.permisions = [permision for permision in permisions[role.id]]
        return roles
        
    async def get_roles_by_user_id(self, user_id: int):
        roles = await self.dao.get_ref([user_id], 'tb_role', 'user_role')
        return roles.get(user_id, None)

    async def update_role_by_user_id(self, request: Request, user_id: int, role_ids: list):
        roles = await self.get_role_permisions_by_user_id(user_id)
        before_role_ids = [p.id for p in roles]
        role_ids = [] if role_ids is None or len(role_ids) == 0 else role_ids
        delete_role_ids = list(set(before_role_ids) - set(role_ids))
        add_role_ids = list(set(role_ids) - set(before_role_ids))
        update_user = self.get_current_user(request).id
        data_db = await self.get_by_id(user_id)
        await self.dao.add_ref(data_db.id, add_role_ids, 'tb_role', 'user_role', update_user)
        await self.dao.delete_ref(data_db.id, delete_role_ids, 'tb_role', 'user_role', update_user)
        
        roles = await self.get_role_permisions_by_user_id(user_id)
        data_db.roles = roles

        return data_db

    async def update_password(self, request: Request, user_id: int, data: UserPasswordIn):
        data_db = await self.get_by_id(user_id)
        if data_db is None:
            raise ServiceException(code=404, message=f"用户不存在")
        if not virify_password(data.password_origin, data_db.password):
            raise ServiceException(code=400, message=f"原密码错误")
        data_update = self.SCHEMA.from_orm(data_db).dict()
        data_update['password'] = password_hash(data.password_new)
        data_update['update_user'] = self.get_current_user(request).id
        return await self.dao.update(data_db.id, data_update)

    async def update_avatar(self, request: Request, user_id: int, avatar: int):
        data_db = await self.get_by_id(user_id)
        if data_db is None:
            raise ServiceException(code=404, message=f"用户不存在")
        update_user = self.get_current_user(request).id
        attachments = await self.dao.get_ref([user_id], 'tb_attachment', 'avatar_attachment')
        if len(attachments.get(user_id, [])) > 0:
            await self.dao.delete_ref(data_db.id, [item.id for item in attachments[user_id]], 'tb_attachment', 'avatar_attachment', update_user)
        await self.dao.add_ref(data_db.id, [avatar], 'tb_attachment', 'avatar_attachment', update_user)
        attachments = await self.dao.get_ref([user_id], 'tb_attachment', 'avatar_attachment')
        data = self.SCHEMA.from_orm(data_db).dict()
        data['avatar'] = attachments[user_id][0].url
        return await self.dao.update(data_db.id, data)



async def check_login_user(request: Request, security_scopes: SecurityScopes, token_data: dict=Depends(get_token_data), service: UserService = Depends(UserService)):
    credentials_exception = HTTPException(
        status_code=status.HTTP_401_UNAUTHORIZED,
        detail="无效凭证",
    )
    if token_data is None:
        logger.error("无效凭证, token_data is None")
        raise credentials_exception
    db_user = await service.first(User(account=token_data['sub']))
    if db_user is None:
        logger.error("无效凭证, db_user is None")
        raise credentials_exception
    if db_user.status != 1:
        logger.error(f"用户已被禁用: {db_user}")
        raise HTTPException(
            status_code=status.HTTP_403_FORBIDDEN,
            detail="用户已被禁用",
        )
    # 判断是否设置了权限域
    if security_scopes.scopes:
        # 未查询用户是否有对应权限
        roles = await service.get_role_permisions_by_user_id(db_user.id)
        permisions = [persision.name for role in roles for persision in role.permisions]
        is_pass = 'admin' in [role.name for role in roles]
        if not is_pass:
            for scope in security_scopes.scopes:
                if scope in permisions:
                    is_pass = True
                    break
        if not is_pass:
            logger.error(f"用户没有权限: {db_user}")
            raise HTTPException(
                status_code=status.HTTP_403_FORBIDDEN,
                detail="Not permissions",
                headers={"scopes": security_scopes.scope_str},
            )
    # 缓存用户ID
    request.state.user = db_user

